/***********************************************************************************************//**
 * \file   app/app.c
 * \brief  Application code
 ***************************************************************************************************
 * <b> (C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
 ***************************************************************************************************
 * This file is licensed under the Silabs License Agreement. See the file
 * "Silabs_License_Agreement.txt" for details. Before using this software for
 * any purpose, you must agree to the terms of that agreement.
 **************************************************************************************************/

/* generated headers */
#include CONFIGURATION_HEADER
#include BOOKKEEPING_HEADER


/* standard library headers */
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>

/* BG stack headers */
#include "bg_types.h"
#ifdef HOST
#include "gecko_bglib.h"
#else /* !HOST */
#include "native_gecko.h"
/* em library */
#include "em_system.h"
#endif /* !HOST */

/* BG stack headers*/
#include "gatt_db.h"

/* application specific headers */
#include "app_cfg.h"
#include "app_hw.h"

/* features */
#ifdef SILABS_AF_PLUGIN_ADVERTISEMENT
#include "advertisement.h"
#endif /* SILABS_AF_PLUGIN_ADVERTISEMENT */
#ifdef SILABS_AF_PLUGIN_BEACON
#include "beacon.h"
#endif /* SILABS_AF_PLUGIN_BEACON */

/* Own header */
#include "app.h"

/***********************************************************************************************//**
 * @addtogroup Application
 * @{
 **************************************************************************************************/

/***********************************************************************************************//**
 * @addtogroup app
 * @{
 **************************************************************************************************/


/***************************************************************************************************
  Local Macros and Definitions
 **************************************************************************************************/

/***************************************************************************************************
 Local Variables
 **************************************************************************************************/

static uint8_t connection;

/***************************************************************************************************
 Function Definitions
 **************************************************************************************************/

void appInit(void)
{
  uint16_t devId;
  struct gecko_msg_system_get_bt_address_rsp_t* btAddr;
#if defined (SILABS_AF_PLUGIN_ADVERTISEMENT) && \
    defined (SILABS_AF_PLUGIN_GAP) && \
    !defined (SILABS_AF_PLUGIN_GAP_DEVNAME_OVERWRITE)
  char devName[APP_DEVNAME_LEN + 1];
#endif /* SILABS_AF_PLUGIN_ADVERTISEMENT &&
          SILABS_AF_PLUGIN_GAP &&
          !SILABS_AF_PLUGIN_GAP_DEVNAME_OVERWRITE */

  /* Create the device name based on the 16-bit device ID */
  btAddr = gecko_cmd_system_get_bt_address();
  devId = *((uint16*)(btAddr->address.addr));
#if defined (SILABS_AF_PLUGIN_ADVERTISEMENT) && \
    defined (SILABS_AF_PLUGIN_GAP) && \
    !defined (SILABS_AF_PLUGIN_GAP_DEVNAME_OVERWRITE)
  /* Write 16-bit device ID to GATT DB. Default behaviour. */
  snprintf(devName, APP_DEVNAME_LEN + 1, APP_DEVNAME, devId);
  gecko_cmd_gatt_server_write_attribute_value(gattdb_device_name,
                                              0,
                                              strlen(devName),
                                              (uint8_t*)devName);
#endif /* SILABS_AF_PLUGIN_ADVERTISEMENT &&
          SILABS_AF_PLUGIN_GAP &&
          !SILABS_AF_PLUGIN_GAP_DEVNAME_OVERWRITE */

  /* AppUi init. */
  appUiInit(devId);
  /* AppHw init. */
  appHwInit();
}

void appHandleEvents(struct gecko_cmd_packet *evt)
{
  uint8_t i; /* Cycle index variable */

  /* Call software event control. */
  /* TODO: this currently runs application events only. This should call stack events as well. */
  runEvents();

  if (NULL == evt) {
    return;
  }

  switch (BGLIB_MSG_ID(evt->header)) {
    /* This event indicates the device has started and is ready to receive any command except
     *  Bluetooth-related commands */
    case gecko_evt_system_boot_id:
      appInit(); /* Has to be called first to set up graphics. */
      appCfgResetEvent();
      break;

    /* This event indicates that a connection was closed. */
    case gecko_evt_le_connection_closed_id:
        appCfgConnectionClosedEvent(evt->data.evt_le_connection_closed.connection,
                                    evt->data.evt_le_connection_closed.reason);
      break;

    /* This event is triggered after the connection has been opened */
    /* todo Read Bonding status */
    case gecko_evt_le_connection_opened_id:
      connection = evt->data.evt_le_connection_opened.connection;
      appCfgConnectionOpenedEvent(connection, evt->data.evt_le_connection_opened.bonding);
      break;

    /* This event is triggered whenever the connection parameters are changed and at any time a
     * connection is established. */
    case gecko_evt_le_connection_parameters_id:
      appCfgConnectionParametersEvent(evt->data.evt_le_connection_parameters.connection,
                                      evt->data.evt_le_connection_parameters.interval,
                                      evt->data.evt_le_connection_parameters.latency,
                                      evt->data.evt_le_connection_parameters.timeout,
                                      evt->data.evt_le_connection_parameters.security_mode);
      break;

    /* Procedure has been successfully completed or failed with error. */
    case gecko_evt_gatt_procedure_completed_id:
      appCfgGattProcCompEvent(evt->data.evt_gatt_procedure_completed.result);
      break;

    /* Value of attribute changed from the local database by remote GATT client */
    case gecko_evt_gatt_server_attribute_value_id:
      for (i = 0; i < appCfgGattServerAttributeValueSize; i++) {
        if ( (appCfgGattServerAttributeValue[i].charId ==
              evt->data.evt_gatt_server_attribute_value.attribute)
             && (appCfgGattServerAttributeValue[i].fctn) ) {
          appCfgGattServerAttributeValue[i].fctn(
              &(evt->data.evt_gatt_server_attribute_value.value));
        }
      }
      break;

    /* Indicates the changed value of CCC or received characteristic confirmation */
    case gecko_evt_gatt_server_characteristic_status_id:
      /* Char status changed */
      if (evt->data.evt_gatt_server_characteristic_status.status_flags == 0x01) {
        for (i = 0; i < appCfgGattServerCharStatusSize; i++) {
          if ( (appCfgGattServerCharStatus[i].charId ==
                evt->data.evt_gatt_server_characteristic_status.characteristic)
               && (appCfgGattServerCharStatus[i].fctn) ) {
            appCfgGattServerCharStatus[i].fctn(
                evt->data.evt_gatt_server_characteristic_status.connection,
                evt->data.evt_gatt_server_characteristic_status.client_config_flags);
          }
        }
      }
      /* Confirmation received */
      else if ((evt->data.evt_gatt_server_characteristic_status.status_flags == 0x02)
    		  /* must be a response to an indication*/
    		  && (evt->data.evt_gatt_server_characteristic_status.client_config_flags == 2)) {
        for (i = 0; i < appCfgGattServerConfirmationSize; i++) {
          if ( (appCfgGattServerConfirmation[i].charId ==
                evt->data.evt_gatt_server_characteristic_status.characteristic)
                 && (appCfgGattServerConfirmation[i].fctn) ) {
        	  appCfgGattServerConfirmation[i].fctn(
                  evt->data.evt_gatt_server_characteristic_status.connection);
          }

        }
      }
      break;

    /* This event indicates that a GATT service at the remote GATT database was discovered */
    case gecko_evt_gatt_service_id:
      appCfgServiceFoundEvent( &(evt->data.evt_gatt_service) );
      break;

    /* This event indicates that a GATT characteristic was discovered from a remote GATT
     * database */
    case gecko_evt_gatt_characteristic_id:
      appCfgChrFoundEvent( &(evt->data.evt_gatt_characteristic) );
      break;

    /* This event indicates that the value of a characteristic at the remote GATT server
     * was received */
    case gecko_evt_gatt_characteristic_value_id:
      appCfgChrValueReceivedEvent( &(evt->data.evt_gatt_characteristic_value) );
      break;

    /* This event indicates that a remote GATT client is attempting to read a value of an
     *  attribute from the local GATT database, where the attribute was defined in the GATT
     *  XML firmware configuration file to have type="user". */
    case gecko_evt_gatt_server_user_read_request_id:
      for (i = 0; i < appCfgGattServerUserReadRequestSize; i++) {
        if ( (appCfgGattServerUserReadRequest[i].charId ==
              evt->data.evt_gatt_server_user_read_request.characteristic)
             && (appCfgGattServerUserReadRequest[i].fctn) ) {
          appCfgGattServerUserReadRequest[i].fctn();
        }
      }
      break;

    /* This event indicates that a remote GATT client is attempting to write a value of an
     * attribute in to the local GATT database, where the attribute was defined in the GATT
     * XML firmware configuration file to have type="user".  */
    case gecko_evt_gatt_server_user_write_request_id:
      for (i = 0; i < appCfgGattServerUserWriteRequestSize; i++) {
        if ( (appCfgGattServerUserWriteRequest[i].charId ==
            evt->data.evt_gatt_server_characteristic_status.characteristic)
            && (appCfgGattServerUserWriteRequest[i].fctn) ) {
          appCfgGattServerUserWriteRequest[i].fctn(
              &(evt->data.evt_gatt_server_attribute_value.value));
        }
      }
      break;

    /* Discovered device scan response */
    case gecko_evt_le_gap_scan_response_id:
      appCfgScanResponse(evt);
      break;

    case gecko_evt_sm_passkey_display_id:
      break;

    case gecko_evt_sm_passkey_request_id:
      break;

    /* This event is triggered after the bonding procedure has been succesfully completed. */
    case gecko_evt_sm_bonded_id:
      appCfgGattBondedEvent( &(evt->data.evt_sm_bonded));
      break;

    case  gecko_evt_sm_bonding_failed_id:
      break;

    case gecko_evt_sm_bonding_request_id:
      break;
  }
}


/** @} (end addtogroup app) */
/** @} (end addtogroup Application) */

